package netWork;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TcpServer {
    private ServerSocket serverSocket = null;

    public TcpServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);

    }

    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true){
            //通过accept方法，把内核中已经建立好的连接拿到应用程序中
            //建立连接的细节流程都是内核自动完成的，应用程序只需要“捡现成”的
            Socket clientSocet = serverSocket.accept();

            processConnection(clientSocet);
        }
    }


    //通过这个方法来处理当前的连接
    public void processConnection(Socket clientSocket) throws IOException {
        //进入方法，先打印一个日志，表示当前有客户端连上了
        System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());

        //进行数据的交互
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()){
            //使用try() 的方式，避免了后续用完了流对象，忘记关闭
            //由于客户端发来的数据，可能是多条数据，针对多条数据，就循环处理
            while(true){
                Scanner scanner = new Scanner(inputStream);
                if(!scanner.hasNext()){
                    //此时连接断开了
                    System.out.printf("[%s:%d] 客户端下载!\n",clientSocket.getInetAddress(),clientSocket.getPort());
                    break;
                }
                //1.读取请求并解析，此处就以next来作为读取请求的方式，next的规则是：读取到“空白符”就返回
                String request = scanner.next();

                //2.根据请求，计算响应
                String response = process(request);

                //3.把响应写回到客户端
                //可以把String转成字符数组，写入到OutputStream
                //也可以使用printWriter 把OutputStream 包裹一下，来写入字符串
                PrintWriter printWriter = new PrintWriter(outputStream);

                //此处的println不是打印到控制台了，
                // 而是写入到outputStream对应的流对象中，也就是写入到clientSocekt里面
                // 自然这个数据也就通过网络发送出去了(发给当前这个连接的另一端)
                // 此处使用println有换行，也是为了后续 客户端那边 可以使用scanner.next  来读取数据
                printWriter.println(response);
                //此处还要记得有一个操作是刷新缓冲区，如果没有刷新缓冲区，可能这个数据仍然是在内存中，没有被写入网卡
                printWriter.flush();
                //4. 打印一下这次的请求交互过程的内容
                System.out.printf("[%s:%d] req = %s, resp  = %s\n",clientSocket.getInetAddress(),
                        clientSocket.getPort(),request,response);

            }
        }catch(IOException e){
            e.printStackTrace();
        } finally{
            try{
                //在这个地方进行clientSocekt的关闭
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public String process(String request){
        //此处也是回显服务器，响应和请求是一样的
        return request;
    }
    public static void main(String[] args) throws IOException{
        TcpServer server = new TcpServer(9090);
        server.start();
    }
}
